import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.vp.*;
import javax.swing.JFrame;


/**
* Eine Demonstration des Picking-Behaviours. Wenn der dargestellte Wuerfel
* angeklickt wird, rotiert er. Die dargestellte Kugel schrumpft und waechst
* abwechselnd.
*
*
* @author Frank Klawonn
* Letzte Aenderung 07.07.2005
* @see PickingExample
*/
public class InteractionExample extends JFrame
{

  //Der Canvas, auf den gezeichnet wird.
  public Canvas3D myCanvas3D;



  public InteractionExample()
  {
    //Mechanismus zum Schliessen des Fensters und beenden des Programms
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


    //Standardeinstellung fuer das Betrachteruniversum
    myCanvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());


    //Aufbau des SimpleUniverse:
    //Zuerst Erzeugen zusammen mit dem Canvas
    SimpleUniverse simpUniv = new SimpleUniverse(myCanvas3D);


    //Standardpositionierung des Betrachters
    simpUniv.getViewingPlatform().setNominalViewingTransform();


    //Die Szene wird in dieser Methode erzeugt.
    createSceneGraph(simpUniv);


    //Hinzufuegen von Licht
    addLight(simpUniv);


    //Hierdurch kann man mit der Maus den Betrachterstandpunkt veraendern
    OrbitBehavior ob = new OrbitBehavior(myCanvas3D);
    ob.setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0),Double.MAX_VALUE));
    simpUniv.getViewingPlatform().setViewPlatformBehavior(ob);


    //Darstellung des Canvas/Fensters:
    setTitle("Klicken Sie die Objekte mit der linken Maustaste an.");
    setSize(700,700);
    getContentPane().add("Center", myCanvas3D);
    setVisible(true);

  }




  public static void main(String[] args)
  {
     InteractionExample interaction = new InteractionExample();
  }





  //In dieser Methode werden die Objekte der Szene aufgebaut und dem
  //SimpleUniverse su hinzugefuegt.
  public void createSceneGraph(SimpleUniverse su)
  {


    //*** Erzeuge einen roten Wuerfel inklusive Transformationsgruppe ***
    Color3f ambientColourFBox = new Color3f(0.5f,0.0f,0.0f);
    Color3f emissiveColourFBox = new Color3f(0.0f,0.0f,0.0f);
    Color3f diffuseColourFBox = new Color3f(0.5f,0.0f,0.0f);
    Color3f specularColourFBox = new Color3f(0.8f,0.0f,0.0f);
    float shininessFBox = 10.0f;

    Appearance fBoxApp = new Appearance();

    fBoxApp.setMaterial(new Material(ambientColourFBox,emissiveColourFBox,
                          diffuseColourFBox,specularColourFBox,shininessFBox));

    Box fBox = new Box(0.2f,0.2f,0.2f,fBoxApp);

    //Die UserData werden benoetigt, um den Wuerfel beim Picking zu identifizieren.
    fBox.setUserData("box");

    TransformGroup tgmBox = new TransformGroup();
    tgmBox.addChild(fBox);

    Transform3D rotationAxis = new Transform3D();


    //Hier wird definiert, wie sich der Wuerfel verhalen soll.
    Alpha boxAlpha = new Alpha(1,2000);

    //Die Startzeit muss zunaechst ins Unendliche verschoben werden:
    boxAlpha.setStartTime(Long.MAX_VALUE);

    RotationInterpolator boxRotation = new RotationInterpolator(boxAlpha,tgmBox,
                                             rotationAxis,0.0f,(float) Math.PI*2);

    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0),Double.MAX_VALUE);
    boxRotation.setSchedulingBounds(bounds);

    //Die Bewegung wird zur Transformationsgruppe hinzugefuegt.
    tgmBox.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    tgmBox.addChild(boxRotation);


    //Eine Transformationsgruppe zur Positionierung des Wuerfels inklusive seiner
    //spaeter auszufuehrenden Rotation
    Transform3D tfFBox = new Transform3D();
    tfFBox.rotY(Math.PI/6);
    Transform3D rotationX = new Transform3D();
    rotationX.rotX(-Math.PI/5);
    tfFBox.mul(rotationX);
    TransformGroup tgFBox = new TransformGroup(tfFBox);
    tgFBox.addChild(tgmBox);


//*** Entsprechendes fuer die Kugel
    Color3f ambientColourBSphere = new Color3f(0.0f,0.6f,0.0f);
    Color3f emissiveColourBSphere = new Color3f(0.0f,0.0f,0.0f);
    Color3f diffuseColourBSphere = new Color3f(0.0f,0.6f,0.0f);
    Color3f specularColourBSphere = new Color3f(0.0f,0.6f,0.0f);
    float shininessBSphere = 2.0f;

    Appearance bSphereApp = new Appearance();

    bSphereApp.setMaterial(new Material(ambientColourBSphere,
                                        emissiveColourBSphere,
                                        diffuseColourBSphere,
                                        specularColourBSphere,
                                        shininessBSphere));

    Sphere bSphere = new Sphere(0.4f,bSphereApp);

    //Die UserData werden benoetigt, um die Kugel beim Picking zu identifizieren.
    bSphere.setUserData("sphere");

    TransformGroup tgmBSphere = new TransformGroup();
    tgmBSphere.addChild(bSphere);


    //Fuer die Kugel muessen zwei Transformation definiert werden: Das
    //Schrumpfen und das Wachsen. Zuerst wird das Schrumpfen definiert.
    Alpha sphereShrinkAlpha = new Alpha(1,2000);

    //Auch hier wird die Ausfuehrung der Transformation zunaechst auf ewig verschoben.
    sphereShrinkAlpha.setStartTime(Long.MAX_VALUE);

    ScaleInterpolator shrinker = new ScaleInterpolator(sphereShrinkAlpha,
                                                       tgmBSphere,
                                                       new Transform3D(),
                                                       1.0f,0.5f);

    shrinker.setSchedulingBounds(bounds);

    tgmBSphere.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    tgmBSphere.addChild(shrinker);


    //Analog fuer das Wachsen der Kugel
    Alpha sphereStretchAlpha = new Alpha(1,2000);
    sphereStretchAlpha.setStartTime(Long.MAX_VALUE);

    ScaleInterpolator stretcher = new ScaleInterpolator(sphereStretchAlpha,
                                                       tgmBSphere,
                                                       new Transform3D(),
                                                       0.5f,1.0f);

    stretcher.setSchedulingBounds(bounds);

    tgmBSphere.addChild(stretcher);


    //Eine transformationsgruppe zur Positionierung der Kugel
    Transform3D tfBSphere = new Transform3D();
    tfBSphere.setTranslation(new Vector3f(2.0f,0.0f,-10.5f));
    TransformGroup tgBSphere = new TransformGroup(tfBSphere);
    tgBSphere.addChild(tgmBSphere);

    //Erzeugung des Szenengraphen
    BranchGroup theScene = new BranchGroup();
    theScene.addChild(tgFBox);
    theScene.addChild(tgBSphere);


    //Definition der Parameter fuer das Picking, Erzeugung des PickingBehaviours
    //und Hinzufuegen zur Szene
    Alpha[] alphas = new Alpha[3];

    alphas[0] = boxAlpha;
    alphas[1] = sphereShrinkAlpha;
    alphas[2] = sphereStretchAlpha;

    PickingExample pe = new PickingExample(myCanvas3D,theScene,bounds,alphas);

    theScene.addChild(pe);


    theScene.compile();

    //Hinzufuegen der Szene
    su.addBranchGraph(theScene);

  }






  //Hier wird etwas Licht zu der Szene hinzugefuegt.
  public void addLight(SimpleUniverse su)
  {

    BranchGroup bgLight = new BranchGroup();

    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), Double.MAX_VALUE);

    //Direktionales Licht
    Color3f lightColour1 = new Color3f(1.0f,1.0f,1.0f);
    Vector3f lightDir1  = new Vector3f(-1.0f,0.0f,-0.5f);
    DirectionalLight light1 = new DirectionalLight(lightColour1, lightDir1);
    light1.setInfluencingBounds(bounds);

    bgLight.addChild(light1);


    //Streulicht
    Color3f lightColourAmb = new Color3f(0.5f, 0.5f, 0.5f);
    AmbientLight lightAmb = new AmbientLight(lightColourAmb);
    lightAmb.setInfluencingBounds(bounds);
    bgLight.addChild(lightAmb);


    su.addBranchGraph(bgLight);

  }

}
